import React, { ComponentType, lazy, Suspense, useEffect, useState } from "react";
import LazyRouter from "./router/lazyRouter";
import { compose, curry, prop, map } from "lodash/fp";
import { Input } from "antd";
import { CurriedFunction3 } from "lodash";
import { InputProps } from "antd/lib/input";

function loading<P>(Com: ComponentType<P>): ComponentType<P & {loading: boolean}> {
  return function ({loading, ...comProps}) {
    if (loading) return <div>loading</div>;
    return <Com {...comProps as P} />;
  }
}

function notFound<P extends { value?: V}, V = any>(Com: ComponentType<P>): ComponentType<P> {
  return function ({value, ...comProps}) {
    if (value === undefined) return <div>Not Found</div>;
      return <Com value={value} {...comProps as any} />;
    }
}

function SimpleShowValue({ value }: {value: string}) {
  return <div>{value}</div>;
}

// loading(notFound(SimpleShowValue));
const OnlyNotFound = compose(loading, notFound)(SimpleShowValue);

function _enableEdit<P>(
  ShowCom: ComponentType<P>,
  Com: ComponentType<P>,
  {editing, ...comProps}: P & {editing: boolean}
) {
  if (editing) return <ShowCom {...comProps as any} />;
  return <Com {...comProps as any} />;
}

const enableEdit = curry(_enableEdit)

function onlyNumber<P extends { value?: any }>(Com: ComponentType<P>): ComponentType<P> {
  return function ({ value, ...rest }) {
    const val = Number(value);
    if (isNaN(val)) {
      return <Com value="NaN" {...rest as any} />;
    }
    return <Com value={value} {...rest as any} />;
  }
}

const withLoadingEditAndNotFound: <T extends { value?: any }>(Com: ComponentType<T>) => React.ComponentType<InputProps & {
  loading: boolean;
  editing: boolean;
}> = compose(loading, enableEdit(Input), notFound);

const Final: React.ComponentType<InputProps & {
  loading: boolean;
  editing: boolean;
  // compose(loading, enableEdit(Input), notFound)(SimpleShowValue);
}> = withLoadingEditAndNotFound(SimpleShowValue);

const andWithOnlyNumber = compose(withLoadingEditAndNotFound, onlyNumber);

const FinalOnlyNumber: React.ComponentType<InputProps & {
  loading: boolean;
  editing: boolean;
}> = andWithOnlyNumber(SimpleShowValue);

// 或者仅仅只使用onlyNumber的功能

const CanEditNumber: React.ComponentType<InputProps & {
  editing: boolean;
  // enableEdit(onlyNumber(Input), SimpleShowValue)
  // enableEdit(onlyNumber(Input))(SimpleShowValue)
  // compose(enableEdit, onlyNumber)(Input)(SimpleShowValue)
}> = compose(enableEdit, onlyNumber)(Input)(SimpleShowValue);

// 所以
const withEditNumber = compose(enableEdit, onlyNumber);

const FinalWithEditNumber: React.ComponentType<InputProps & {
  loading: boolean;
  editing: boolean;
  // compose(loading, enableEdit(onlyNumber(Input)), notFound)(SimpleShowValue);
  // loading(enableEdit(onlyNumber(Input), notFound(SimpleShowValue)))
  // 1 -> loading(enableEdit(onlyNumber(Input))(notFound(SimpleShowValue)))
  // 1 -> loading(compose(enableEdit, onlyNumber)(Input)(notFound(SimpleShowValue)))
  // 1 -> compose(loading, compose(enableEdit, onlyNumber)(Input), notFound)(SimpleShowValue);
    
  // 2 -> compose(loading, enableEdit)(onlyNumber(Input), notFound(SimpleShowValue))
}> = compose(loading, enableEdit)(onlyNumber(Input), notFound(SimpleShowValue));

function App() {
  const [val, setVal] = useState('');
  return (
  <>
    <Final loading editing />
    <div>
      2. 不loading开启editing
      <Final loading={false} editing />
    </div>
    <div>
      3. 不loading不editing
      <Final loading={false} editing={false} value="123" />
    </div>
    <div>
      4. 不loading开启editing value=123
      <Final loading={false} editing value="123" />
    </div>
    <div>
      5. 开启loading
      <Final loading editing={false} value="123" />
    </div>
    <div>
      6. 开启loading
      <Final loading editing={false} />
    </div>
    <div>
      7. FinalOnlyNumber 开启loading
      <FinalOnlyNumber loading editing={false} />
    </div>
    <div>
      8. FinalOnlyNumber 关闭loading 关闭editing 不设置value
      <FinalOnlyNumber loading={false} editing={false} />
    </div>
    <div>
      9. FinalOnlyNumber 关闭loading 关闭editing value="123"
      <FinalOnlyNumber loading={false} editing={false} value="123" />
    </div>
    <div>
      10. FinalOnlyNumber 关闭loading 关闭editing value="a"
      <FinalOnlyNumber loading={false} editing={false} value="a" />
    </div>
    <div>
      11. FinalOnlyNumber 关闭loading 关闭editing value={456}
      <FinalOnlyNumber loading={false} editing={false} value={456} />
    </div>
    <div>
      12. FinalOnlyNumber 关闭loading 开启editing value={456}
      <FinalOnlyNumber loading={false} editing value={456} />
    </div>
    <CanEditNumber editing />
    <CanEditNumber editing value={789} />
    <div>
      13. CanEditNumber 开启editing 开启受控
      <CanEditNumber editing value={val} onChange={e => setVal(e.target.value)} />
    </div>
    <div>
      14. FinalWithEditNumber
      <FinalWithEditNumber loading editing />
    </div>
    <div>
      15. FinalWithEditNumber 关闭loading
      <FinalWithEditNumber loading={false} editing />
    </div>
  </>
  );
}

export default App;
